package com.qqtech.pay;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.qqtech.core.common.annotation.VisitAnnt;
import com.qqtech.core.common.constant.CoreConst;
import com.qqtech.core.common.enums.RespEnum;
import com.qqtech.core.common.util.ArithUtil;
import com.qqtech.core.common.util.HttpUtil;
import com.qqtech.core.common.util.StringUtil;
import com.qqtech.core.frame.model.Result;
import com.qqtech.core.frame.service.BaseService;
import com.qqtech.pay.ali.AlipayCfg;
import com.qqtech.pay.ali.AlipayNotify;
import com.qqtech.pay.wx.WxpayCore;
import com.qqtech.qquan.order.enums.OrderPayWayDictEnum;
import com.qqtech.qquan.order.model.OrderAlipayConfigBean;
import com.qqtech.qquan.order.model.OrderBase;
import com.qqtech.qquan.order.model.OrderBaseQuery;
import com.qqtech.qquan.order.model.OrderPayLog;
import com.qqtech.qquan.order.model.OrderPayWayBean;
import com.qqtech.qquan.order.model.OrderWxpayConfigBean;
import com.qqtech.qquan.order.service.OrderBaseService;
import com.qqtech.qquan.order.service.OrderHandleService;
import com.qqtech.qquan.sys.enums.SysConst;
import com.qqtech.qquan.sys.model.SysParam;
import com.qqtech.qquan.sys.service.SysParamService;
import com.qqtech.qquan.user.service.UserMoneyLogService;
import com.qqtech.web.context.BaseWebController;

@Controller
@RequestMapping(value = "/pay")
public class PayController extends BaseWebController<OrderBase, OrderBaseQuery> {
	public static final Logger log = LoggerFactory.getLogger(PayController.class);
	@Resource
	private OrderBaseService orderBaseService;
	@Resource
	private OrderHandleService orderHandleService;
	@Resource
	private OrderPayWayBean orderPayWayBean;
	@Resource
	private OrderAlipayConfigBean orderAlipayConfigBean;
	@Resource
	private OrderWxpayConfigBean orderWxpayConfigBean;
	@Resource
	private UserMoneyLogService userMoneyLogService;
	@Resource
	private SysParamService sysParamService;

	@Override
	protected BaseService<OrderBase> getBaseService() {
		return orderBaseService;
	}

	@RequestMapping(value = "/wxNotifyUrl")
	public void wxNotifyUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
		Map<String, Object> paramMap = null;
		boolean flag = false;
		try {
			paramMap = WxpayCore.getInstance().parseParam(request);
		} catch (IOException e) {
			log.error("解析微信同步的请求参数出错,e={},{}", e, e.getStackTrace());
			writeData(WxpayCore.getInstance().notifyBack(flag), response);
			return;
		}
		flag = WxpayCore.getInstance().verify(paramMap);
		String orderNo = (String) paramMap.get("out_trade_no");
		String tradeNo = (String) paramMap.get("transaction_id");
		if (flag) {
			if (StringUtil.isNotBlank(orderNo)) {
				orderNo = orderNo.substring(0, orderNo.lastIndexOf("-"));
			}
			String payUserId = (String) paramMap.get("attach");
			OrderPayLog orderPayLog = new OrderPayLog();
			orderPayLog.setOrderNo(orderNo);
			orderPayLog.setTradeNo(tradeNo);
			if (StringUtil.isNotBlank(payUserId)) {
				orderPayLog.setPayUserId(new Integer(payUserId));
			}
			orderPayLog.setBuyerEmail((String) paramMap.get("openid"));
			orderPayLog.setBuyerId((String) paramMap.get("openid"));
			orderPayLog.setValue(new BigDecimal((String) paramMap.get("total_fee")).divide(new BigDecimal(100)));
			orderPayLog.setPayWay(OrderPayWayDictEnum.WEIXIN.getCode());
			orderHandleService.payOrder(orderPayLog);
			writeData(WxpayCore.getInstance().notifyBack(flag), response);
		}
	}

	@RequestMapping(value = "/aliNotifyUrl")
	public void aliNotifyUrl(HttpServletRequest request, HttpServletResponse response) {
		try {
			Map<String, String> params = new HashMap<String, String>();
			String reqBody = HttpUtil.getRequestBody(request);
			if (StringUtil.isBlank(reqBody)) {
				Enumeration<String> paramNames = request.getParameterNames();
				while (paramNames.hasMoreElements()) {
					String paramName = (String) paramNames.nextElement();
					String[] paramValues = request.getParameterValues(paramName);
					if (paramValues.length == 1) {
						String paramValue = paramValues[0];
						if (StringUtil.isNotBlank(paramValue)) {
							params.put(paramName, paramValue);
						}
					}
				}
			} else {
				String[] paramArr = reqBody.split("&");
				if (paramArr != null && paramArr.length > 0) {
					for (String paramKV : paramArr) {
						if (StringUtil.isNotBlank(paramKV)) {
							String[] kvArr = paramKV.split("=");
							if (kvArr != null && kvArr.length == 2) {
								if (StringUtil.isNotBlank(kvArr[0]) && StringUtil.isNotBlank(kvArr[1])) {
									params.put(URLDecoder.decode(kvArr[0], CoreConst.DEFAULT_CODETYPE),
											URLDecoder.decode(kvArr[1], CoreConst.DEFAULT_CODETYPE));
								}
							}
						}
					}
				}
			}
			String msg = "";
			// 交易状态
			String trade_status = params.get("trade_status");
			// 异步通知ID
			String notify_id = params.get("notify_id");
			// sign
			String sign = params.get("sign");
			if (StringUtil.isNotBlank(notify_id)) {
				if (AlipayNotify.verifyResponse(notify_id).equals("true")) {
					if (AlipayNotify.getSignVeryfy(params, sign)) {
						String sellerId = params.get("seller_id");
						if (StringUtil.isNotBlank(sellerId)
								&& sellerId.equals(AlipayCfg.getInstance().getValue("partner"))) {
							if (trade_status.equals("TRADE_FINISHED")) {
								// 订单彻底完成(高级版会在TRADE_SUCCESS请求后的三个月后发来TRADE_FINISHED状态)，以后支付宝不会再请求来这里
							} else if (trade_status.equals("TRADE_SUCCESS")) {
								// 钱充值到账马上会有这状态发来
								String payUserId = params.get("body");
								OrderPayLog orderPayLog = new OrderPayLog();
								orderPayLog.setOrderNo(params.get("out_trade_no"));
								orderPayLog.setTradeNo(params.get("trade_no"));
								if (StringUtil.isNotBlank(payUserId)) {
									orderPayLog.setPayUserId(new Integer(payUserId));
								}
								orderPayLog.setBuyerEmail(params.get("buyer_email"));
								orderPayLog.setBuyerId(params.get("buyer_id"));
								orderPayLog.setValue(new BigDecimal(params.get("total_fee")));
								orderPayLog.setPayWay(OrderPayWayDictEnum.ALIPAY.getCode());
								orderHandleService.payOrder(orderPayLog);
							}
						}
						msg = "success";
					} else {// 验证签名失败
						msg = "sign fail";
					}
				} else {// 验证是否来自支付宝的通知失败
					msg = "response fail";
				}
			} else {
				msg = "no notify message";
			}
			this.writeData(msg, response);
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
		}
	}

	private void writeData(String msg, HttpServletResponse response) {
		PrintWriter writer = null;
		try {
			writer = response.getWriter();
			writer.write(msg);
			writer.flush();
		} catch (IOException e) {
			log.error("返回信息时出错,msg={}", msg);
		} finally {
			if (null != writer) {
				writer.close();
			}
		}
	}

	@VisitAnnt(type = RespEnum.LOGIN)
	@RequestMapping(value = "/checkForPay")
	@ResponseBody
	public Result checkForPay(@RequestBody Map<String, String> map) {
		Result result = new Result();
		if (map == null) {
			result.addErr("参数有误");
			return result;
		}
		String orderNo = map.get("orderNo");
		if (StringUtil.isBlank(orderNo)) {
			result.addErr("参数有误");
			return result;
		}
		if (orderPayWayBean == null) {
			result.addErr("系统暂不支持支付");
			return result;
		}
		result = orderBaseService.checkForPay(orderNo, super.getUserId());
		if (result.checkForm()) {
			result.put("payWay", orderPayWayBean);
		}
		return result;
	}

	@VisitAnnt(type = RespEnum.LOGIN)
	@RequestMapping(value = "/getPayByOrderNo")
	@ResponseBody
	public Result getPayByOrderNo(@RequestBody Map<String, String> map, HttpServletRequest request) {
		Result result = new Result();
		try {
			if (map == null) {
				result.addErr("参数有误");
				return result;
			}
			String orderNo = map.get("orderNo");
			if (StringUtil.isBlank(orderNo)) {
				result.addErr("参数有误");
				return result;
			}
			String ddtOnline = map.get("ddtOnline");
			if (StringUtil.isBlank(ddtOnline)) {
				result.addErr("参数有误");
				return result;
			}
			if (orderPayWayBean == null) {
				result.addErr("系统暂不支持支付");
				return result;
			}
			if (orderAlipayConfigBean == null) {
				result.addErr("订单参数有误");
				return result;
			}
			result = orderBaseService.checkForPay(orderNo, super.getUserId());
			if (!result.checkForm()) {
				return result;
			}
			int type4Online100 = ((Double) result.get("type4Online100")).intValue();
			int quanInt = 0;
			int moneyInt = 0;
			int onlineInt = 0;
			String ddtQuan = map.get("ddtQuan");
			if (StringUtil.isNotBlank(ddtQuan)) {
				quanInt = new Integer(ddtQuan).intValue();
			}
			String ddtMoney = map.get("ddtMoney");
			if (StringUtil.isNotBlank(ddtMoney)) {
				moneyInt = new Integer(ddtMoney).intValue();
			}
			onlineInt = new Double(ArithUtil.round(new Double(ddtOnline) * CoreConst.VALUE_CORE_MONEYRATE, 0))
					.intValue();
			if (onlineInt <= 0 || (quanInt + moneyInt + onlineInt) != type4Online100) {
				result.addErr("支付数据有误，请重新支付");
				return result;
			}
			if (quanInt > 0) {
				double validQuan = userMoneyLogService.getValidQuan(super.getUserId());
				int validQuanInt = new Double(ArithUtil.round(validQuan * CoreConst.VALUE_CORE_MONEYRATE, 0))
						.intValue();
				if (quanInt > validQuanInt) {
					result.addErr("您的圈币不足" + quanInt + "，无法抵扣，请返回重新支付");
					return result;
				}
				BigDecimal qqRate = (BigDecimal) result.get("qqRate");
				BigDecimal shopRate = (BigDecimal) result.get("shopRate");
				double shopQuan = ArithUtil.roundMoney(new BigDecimal(quanInt)
						.multiply(shopRate.divide(qqRate.add(shopRate), 2, BigDecimal.ROUND_HALF_EVEN)));
				userMoneyLogService.payWithUserQuan(orderNo, (String) result.get("buyerId"), super.getUserId(), quanInt,
						"订单(" + orderNo + ")支付",
						new BigDecimal(ArithUtil.round(new Double(shopQuan) / CoreConst.VALUE_CORE_MONEYRATE, 2)),
						shopRate);
			}
			if (moneyInt > 0) {
				double validMoney = userMoneyLogService.getValidMoney(super.getUserId());
				int validMoneyInt = new Double(ArithUtil.round(validMoney * CoreConst.VALUE_CORE_MONEYRATE, 0))
						.intValue();
				if (moneyInt > validMoneyInt) {
					result.addErr("您的余额不足" + moneyInt + "，无法抵扣，请返回重新支付");
					return result;
				}
				userMoneyLogService.payWithUserMoney(orderNo, (String) result.get("buyerId"), super.getUserId(),
						moneyInt, "订单(" + orderNo + ")支付");
			}

			String payWay = map.get("payWay");
			String appName = "圈圈生活";
			SysParam sysParam = sysParamService.getByKey(SysConst.PARAMVALUE_SYS_PRODUCT_NAME);
			if (sysParam != null && StringUtil.isNotBlank(sysParam.getValue())) {
				appName = sysParam.getValue();
			}
			appName = appName + "-";
			if (("" + OrderPayWayDictEnum.ALIPAY.getCode()).equals(payWay)) {
				orderAlipayConfigBean.setTradeNo(orderNo);
				orderAlipayConfigBean.setTotalFee(ddtOnline);
				orderAlipayConfigBean.setSubject(appName + (String) result.get("title"));
				orderAlipayConfigBean.setBody("" + super.getUserId());
				result.put("aliPay", orderAlipayConfigBean);
			} else if (("" + OrderPayWayDictEnum.WEIXIN.getCode()).equals(payWay)) {
				orderWxpayConfigBean.setAttach("" + super.getUserId());
				orderWxpayConfigBean.setOutTradeNo(orderNo + "-" + StringUtil.getRandomNum(3));
				orderWxpayConfigBean.setSpbillCreateIp(StringUtil.getClientIp(request));
				orderWxpayConfigBean.setBody(appName + (String) result.get("title"));
				orderWxpayConfigBean.setTotalFee(onlineInt);
				result.put("wxPay", getOtherWxpayConfig(orderWxpayConfigBean));
			}
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(RespEnum.EXCEPTION, "支付失败，请回到订单重新支付");
		}
		return result;
	}

	public static void main(String[] s) {
		String d = "fdf454646-fdfe5";
		System.out.println(d.substring(0, d.lastIndexOf("-")));
	}

	private OrderWxpayConfigBean getOtherWxpayConfig(OrderWxpayConfigBean orderWxpayConfigBean) {
		WxpayCore wxPayCore = WxpayCore.getInstance();
		SortedMap<String, Object> paramMap = new TreeMap<String, Object>();
		String nonceStr = wxPayCore.getNonceStr();
		String appId = orderWxpayConfigBean.getAppId();
		String partnerId = orderWxpayConfigBean.getPartnerId();
		paramMap.put("appid", appId);
		paramMap.put("attach", orderWxpayConfigBean.getAttach());
		paramMap.put("body", orderWxpayConfigBean.getBody());
		paramMap.put("mch_id", partnerId);
		paramMap.put("notify_url", orderWxpayConfigBean.getNotifyUrl());
		paramMap.put("nonce_str", nonceStr);
		paramMap.put("out_trade_no", orderWxpayConfigBean.getOutTradeNo());
		paramMap.put("spbill_create_ip", orderWxpayConfigBean.getSpbillCreateIp());
		// 总金额，单位[分]
		String totalFee = String.valueOf(orderWxpayConfigBean.getTotalFee());
		paramMap.put("total_fee", totalFee);
		paramMap.put("trade_type", orderWxpayConfigBean.getTradeType());
		// 签名
		String signStr = wxPayCore.createSign(paramMap);
		paramMap.put("sign", signStr);
		// 组装请求参数
		String xml = wxPayCore.createXml(paramMap);
		// 获取预支付ID
		String prepayId = wxPayCore.getPrepayData(orderWxpayConfigBean.getPostUrl(), xml);
		paramMap.clear();
		Long timeStamp = System.currentTimeMillis() / 1000;
		nonceStr = wxPayCore.getNonceStr();
		paramMap.put("appid", appId);
		paramMap.put("partnerid", partnerId);
		paramMap.put("prepayid", prepayId);
		paramMap.put("noncestr", nonceStr);
		paramMap.put("package", orderWxpayConfigBean.getPackageStr());
		paramMap.put("timestamp", timeStamp);
		signStr = wxPayCore.createSign(paramMap);
		orderWxpayConfigBean.setPrepayId(prepayId);
		orderWxpayConfigBean.setSign(signStr);
		orderWxpayConfigBean.setTimeStamp("" + timeStamp);
		orderWxpayConfigBean.setNonceStr(nonceStr);
		return orderWxpayConfigBean;
	}

	// "orderNo":orderNo,"ddtQuan":""+ddtQuan,"ddtMoney":""+ddtMoney,"ddtOnline":""+ddtOnline
	@VisitAnnt(type = RespEnum.LOGIN)
	@RequestMapping(value = "/payDeduction")
	@ResponseBody
	public Result payDeduction(@RequestBody Map<String, String> map, HttpServletRequest request) {
		Result result = new Result();
		try {
			if (map == null) {
				result.addErr("参数有误");
				return result;
			}
			String orderNo = map.get("orderNo");
			if (StringUtil.isBlank(orderNo)) {
				result.addErr("参数有误");
				return result;
			}
			if (StringUtil.isBlank(map.get("ddtQuan")) && StringUtil.isBlank(map.get("ddtMoney"))) {
				result.addErr("参数有误");
				return result;
			}
			result = orderBaseService.checkForPay(orderNo, super.getUserId());
			if (!result.checkForm()) {
				return result;
			}

			int type4Online100 = ((Double) result.get("type4Online100")).intValue();
			int quanInt = 0;
			int moneyInt = 0;
			String ddtQuan = map.get("ddtQuan");
			if (StringUtil.isNotBlank(ddtQuan)) {
				quanInt = new Integer(ddtQuan).intValue();
			}
			String ddtMoney = map.get("ddtMoney");
			if (StringUtil.isNotBlank(ddtMoney)) {
				moneyInt = new Integer(ddtMoney).intValue();
			}
			if (quanInt < 0 || moneyInt < 0 || (quanInt + moneyInt) != type4Online100) {
				result.addErr("支付数据有误，请重新支付");
				return result;
			}
			if (quanInt > 0) {
				double validQuan = userMoneyLogService.getValidQuan(super.getUserId());
				int validQuanInt = new Double(ArithUtil.round(validQuan * CoreConst.VALUE_CORE_MONEYRATE, 0))
						.intValue();
				if (quanInt > validQuanInt) {
					result.addErr("您的圈币不足" + quanInt + "，无法抵扣，请返回重新支付");
					return result;
				}
				BigDecimal qqRate = (BigDecimal) result.get("qqRate");
				BigDecimal shopRate = (BigDecimal) result.get("shopRate");
				double shopQuan = ArithUtil.roundMoney(new BigDecimal(quanInt)
						.multiply(shopRate.divide(qqRate.add(shopRate), 2, BigDecimal.ROUND_HALF_EVEN)));
				userMoneyLogService.payWithUserQuan(orderNo, (String) result.get("buyerId"), super.getUserId(), quanInt,
						"订单(" + orderNo + ")支付",
						new BigDecimal(ArithUtil.round(new Double(shopQuan) / CoreConst.VALUE_CORE_MONEYRATE, 2)),
						shopRate);
			}
			if (moneyInt > 0) {
				double validMoney = userMoneyLogService.getValidMoney(super.getUserId());
				int validMoneyInt = new Double(ArithUtil.round(validMoney * CoreConst.VALUE_CORE_MONEYRATE, 0))
						.intValue();
				if (moneyInt > validMoneyInt) {
					result.addErr("您的余额不足" + moneyInt + "，无法抵扣，请返回重新支付");
					return result;
				}
				userMoneyLogService.payWithUserMoney(orderNo, (String) result.get("buyerId"), super.getUserId(),
						moneyInt, "订单(" + orderNo + ")支付");
			}
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(RespEnum.EXCEPTION, "支付失败，请回到订单重新支付");
		}
		return result;
	}
}